package com.dhms.vostok1.model

import android.util.Log
import androidx.lifecycle.*
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.dhms.uikit.deviceCategory.DeviceItem
import com.dhms.vostok1.data.ApiResult
import com.dhms.vostok1.data.ApiState
import com.dhms.vostok1.data.DEFAULT_PAGE_LIMIT
import com.dhms.vostok1.data.DEFAULT_PAGE_OFFSET
import com.dhms.vostok1.data.fault.FaultLevelListData
import com.dhms.vostok1.data.fault.FaultListItemData
import com.dhms.vostok1.data.fault.FaultListQueryData
import com.dhms.vostok1.data.fault.FaultStatisticResData
import com.dhms.vostok1.repository.FaultListPagingSource
import com.dhms.vostok1.repository.FaultRepository
import com.dhms.vostok1.repository.FaultRepository.Companion.DEFAULT_FAULT_LEVEL_LIST
import com.dhms.vostok1.service.net.NetworkApi
import com.dhms.vostok1.utils.secondTimeStamp
import com.dhms.vostok1.utils.toMap
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.launch
import java.util.*
import java.util.concurrent.CopyOnWriteArraySet

class FaultViewModel(
    private val faultRepository: FaultRepository
) : ViewModel() {
    private val _selectedFaultStatus =
        MutableLiveData<CopyOnWriteArraySet<String>>(CopyOnWriteArraySet())
    private val _quickSettingSource = MutableLiveData<Int?>()
    private val _faultSearchConditions = MutableLiveData(
        FaultListQueryData(
            limit = DEFAULT_PAGE_LIMIT,
            offset = DEFAULT_PAGE_OFFSET,
        )
    )
    private val _faultLevelList = MutableLiveData(DEFAULT_FAULT_LEVEL_LIST)
    private val _faultStatisticData = MutableLiveData<FaultStatisticResData?>(null)
    private val _getFaultStatisticDataResult = MutableLiveData<ApiResult?>(null)
    private val _faultCount = MutableLiveData<Int?>(null)
    private val _searchDevice = MutableLiveData<DeviceItem>()
    private val _latestFaultList = MutableLiveData<List<FaultListItemData>?>()
    private val _getLatestFaultListResult = MutableLiveData<ApiResult?>()

    val selectedFaultStatus: LiveData<CopyOnWriteArraySet<String>> = _selectedFaultStatus
    val quickSettingSource: LiveData<Int?> = _quickSettingSource
    val faultSearchConditions: LiveData<FaultListQueryData> = _faultSearchConditions
    val faultLevelList: LiveData<FaultLevelListData> = _faultLevelList
    val faultStatisticData: LiveData<FaultStatisticResData?> = _faultStatisticData
    val faultCount: LiveData<Int?> = _faultCount
    val searchDevice: LiveData<DeviceItem> = _searchDevice
    val latestFaultList: LiveData<List<FaultListItemData>?> = _latestFaultList
    val getLatestFaultListResult: LiveData<ApiResult?> = _getLatestFaultListResult

    fun clearFaultCount() {
        _faultCount.value = null
    }

    fun getFaultList(): Flow<PagingData<FaultListItemData>> {
        faultSearchConditions.value?.let {
            it.paUseType
            return Pager(
                PagingConfig(pageSize = DEFAULT_PAGE_LIMIT),
                initialKey = DEFAULT_PAGE_OFFSET
            ) {
                FaultListPagingSource(NetworkApi, faultSearchConditions.value!!, _faultCount)
            }.flow
        }
        return object : Flow<PagingData<FaultListItemData>> {
            override suspend fun collect(collector: FlowCollector<PagingData<FaultListItemData>>) {
            }
        }
    }

    fun getLatestFaultList() {
        if (getLatestFaultListResult.value?.state == ApiState.LOADING) {
            return
        }
        _getLatestFaultListResult.value = ApiResult(ApiState.LOADING)
        viewModelScope.launch {
            val queryData = FaultListQueryData(
                limit = 5,
                offset = 1,
                faStatus = "occurred,accepted"
            )
            val resData = NetworkApi.getFaultList(queryData.toMap()!!)

            val error = resData.exceptionOrNull()
            if (error != null) {
                _getLatestFaultListResult.value =
                    ApiResult(ApiState.ERROR, error.message ?: "获取失败！")
                return@launch
            }

            val data = resData.getOrNull()?.body()?.data?.data
            _latestFaultList.value = data
            _getLatestFaultListResult.value = ApiResult(ApiState.DONE)
        }
    }

    fun setFaultSearchTimeRange(startTime: String?, endTime: String?, sourceId: Int?) {
        val condition =
            faultSearchConditions.value?.copy(occurredStart = startTime, occurredEnd = endTime)
        _faultSearchConditions.value = condition
        _quickSettingSource.value = sourceId
    }

    fun addFaultSearchStatus(status: String) {
        _selectedFaultStatus.value?.let {
            it.add(status)
            val condition =
                faultSearchConditions.value?.copy(faStatus = it.joinToString(separator = ","))
            _faultSearchConditions.value = condition
        }
    }

    fun removeFaultSearchStatus(status: String) {
        _selectedFaultStatus.value?.let {
            it.remove(status)
            val condition =
                faultSearchConditions.value?.copy(faStatus = it.joinToString())
            _faultSearchConditions.value = condition
        }
    }

    fun getFaultStatisticData() {
        _getFaultStatisticDataResult.value = ApiResult(ApiState.LOADING)
        viewModelScope.launch {
            val queryMap = mapOf(
                "from" to "1",
                "to" to Date().secondTimeStamp().toString(),
            )
            val res = NetworkApi.getFaultStatisticData(
                queryMap,
                "occurred",
                "accepted",
                "observing",
                "1",
                "5"
            )
            Log.d(TAG, "The res to get device state statistic data is: $res.")

            val error = res.exceptionOrNull()
            if (error != null) {
                _faultStatisticData.value = null
                _getFaultStatisticDataResult.value =
                    ApiResult(ApiState.ERROR, error.message ?: "获取失败！")
                Log.e(TAG, "error: $error")

                return@launch
            }

            val resData = res.getOrNull()?.body()?.data
            _faultStatisticData.value = resData ?: listOf()
            _getFaultStatisticDataResult.value = ApiResult(ApiState.DONE)
        }
    }

    fun setFilterSelectedDevices(devices: List<DeviceItem>?) {
        this._searchDevice.value = if (devices.isNullOrEmpty()) null else devices.last()
        val condition =
            faultSearchConditions.value?.copy(deviceId = searchDevice.value?.de_id)
        _faultSearchConditions.value = condition
    }

    companion object {
        private const val TAG = "FaultViewModel"
//        private const val SEARCH_CONDITION_KEY_DEVICE_ID = "SEARCH_CONDITION_KEY_DEVICE_ID"
//        private const val SEARCH_CONDITION_KEY_DEVICE_CATEGORY_ID = "SEARCH_CONDITION_KEY_DEVICE_CATEGORY_ID"
//        private const val SEARCH_CONDITION_KEY_PA_USE_TYPE = "SEARCH_CONDITION_KEY_PA_USE_TYPE"
//        private const val SEARCH_CONDITION_KEY_PA_STATUS = "SEARCH_CONDITION_KEY_PA_STATUS"
//        private const val SEARCH_CONDITION_KEY_OCCURRED_START = "SEARCH_CONDITION_KEY_OCCURRED_START"
//        private const val SEARCH_CONDITION_KEY_OCCURRED_END = "SEARCH_CONDITION_KEY_OCCURRED_END"
    }
}

class FaultViewModelFactory(
    private val faultRepository: FaultRepository
) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(FaultViewModel::class.java)) {
            @Suppress("UNCHECKED_CAST")
            return FaultViewModel(faultRepository) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}
